﻿using System;
using System.Text;
using Sixeyed.CodeGeneration.Metadata.Interfaces;

namespace Sixeyed.CodeGeneration.Generation
{
    /// <summary>
    /// Configuration for a T4 template to be run over metadata items
    /// </summary>
    public class TemplateConfiguration : ICloneable
    {
        #region Private instace fields

        private string _templatePath;
        private string _targetNamespace;
        private string _className;
        private string _fileExtension;
        private string _fileName;

        #endregion

        #region Public properties

        /// <summary>
        /// Full path to the T4 template file
        /// </summary>
        public string TemplatePath
        {
            get { return this._templatePath; }
            set { this._templatePath = value; }
        }

        /// <summary>
        /// Target namespace for generated classes
        /// </summary>
        public string TargetNamespace
        {
            get { return _targetNamespace; }
            set { _targetNamespace = value; }
        }

        /// <summary>
        /// Name for generated class
        /// </summary>
        public string ClassName
        {
            get { return _className; }
            set { _className = value; }
        }

        /// <summary>
        /// Extension for generated file
        /// </summary>
        public string FileExtension
        {
            get { return _fileExtension; }
            set { _fileExtension = value; }
        }

        /// <summary>
        /// Name for generated file
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }

        #endregion

        #region Public instance methods

        /// <summary>
        /// Gets the full filename of the target file
        /// </summary>
        /// <returns>Target filename</returns>
        public string GetTargetFileName()
        {
            string fileName = this._fileName;
            if (string.IsNullOrEmpty(this._fileName) &&
                !string.IsNullOrEmpty(this._className) &&
                !string.IsNullOrEmpty(this._fileExtension))
            {
                fileName = string.Format("{0}.{1}", this._className, this._fileExtension.TrimStart('.'));
            }
            else if (!string.IsNullOrEmpty(this._fileName) &&
                !string.IsNullOrEmpty(this._fileExtension))
            {
                fileName = string.Format("{0}.{1}", this._fileName, this._fileExtension.TrimStart('.'));
            }
            return fileName; 
        }

        /// <summary>
        /// Returns string representation of code generation attributes
        /// </summary>
        /// <remarks>
        /// Use for adding generation attributes to types, allowing the item to be regenerated
        /// </remarks>
        /// <param name="item">Metadata item</param>
        /// <returns>Attribute string, specifying generation source, provider and template</returns>
        public string GetGeneratedCodeAttributes(IMetadataItem item)
        {
            string sourceAttribute = string.Format("[Sixeyed.CodeGeneration.Attributes.GeneratedCodeSource(\"{0}\", @\"{1}\")]", item.Provider.Source.GetType().FullName, item.Provider.Source.Uri);
            string providerAttribute = string.Format("[Sixeyed.CodeGeneration.Attributes.GeneratedCodeProvider(\"{0}\", @\"{1}\")]", item.Provider.GetType().FullName, item.Key);
            string templateAttribute = string.Format("[Sixeyed.CodeGeneration.Attributes.GeneratedCodeTemplate(@\"{0}\", \"{1}\", \"{2}\", \"{3}\")]", this.TemplatePath, this.TargetNamespace, this.ClassName, this.FileName);
            
            StringBuilder attributeBuilder = new StringBuilder();
            attributeBuilder.AppendFormat("{0}{1}", sourceAttribute, Environment.NewLine);
            attributeBuilder.AppendFormat("    {0}{1}", providerAttribute, Environment.NewLine);
            attributeBuilder.AppendFormat("    {0}", templateAttribute);
            
            return attributeBuilder.ToString();
        }

        /// <summary>
        /// Populates missing properties from the given configuration object
        /// </summary>
        /// <param name="templateConfiguration">Configuration object to load from</param>
        public void LoadFrom(TemplateConfiguration templateConfiguration)
        {
            if (string.IsNullOrEmpty(this._className))
            {
                this._className = templateConfiguration._className;
            }
            if (string.IsNullOrEmpty(this._fileExtension))
            {
                this._fileExtension = templateConfiguration._fileExtension;
            }
            if (string.IsNullOrEmpty(this._fileName))
            {
                this._fileName = templateConfiguration._fileName;
            }
            if (string.IsNullOrEmpty(this._targetNamespace))
            {
                this._targetNamespace = templateConfiguration._targetNamespace;
            }
            if (string.IsNullOrEmpty(this._templatePath))
            {
                this._templatePath = templateConfiguration._templatePath;
            }
        }

        #endregion

        #region ICloneable Members

        /// <summary>
        /// Returns a clone of the current object
        /// </summary>
        /// <returns>Clone</returns>
        public object Clone()
        {
            TemplateConfiguration templateConfiguration = new TemplateConfiguration();
            templateConfiguration.LoadFrom(this);
            return templateConfiguration;
        }

        #endregion
    }
}
